﻿using System;

namespace Csharp结构体学习_数组学习_方法学习
{
    #region  描述学生的信息
    struct StuInform 
    {
        public string name;
        public string sex;
        public int age;
        public string hobby;
        
    }
    #endregion

    #region 描述二维坐标
    struct vector 
    {
        public int x;
        public int y;
    }
    #endregion

    #region 定义一个怪物
    //定义一个怪物
    struct Monster 
    {
        public string name;
        public int atk;
        public int hp;

        //定义一个方法，因为方法可以定义在结构体中
        //考虑是静态还是非静态（对象是否实例化）能实例化就用非静态的,就不写static

        //攻击别的monster————monster类型
        public void Attack(ref Monster monster)
        //1.在定义函数的参数列表时，把你想要的索引的值类型的那个参数前加上ref
        {
            monster.hp = monster.hp - this.atk;//扣血量根据自身的攻击力来扣--区分敌方atk和我方atk
            //this是自身的---意思是目标monster减去了自身的血量
        }


    
    }
    #endregion

    #region 定义结构体用户信息
    struct UserInfo
    {
        public string userName, password, info;//info 多返回一个信息

    }

    #endregion

    class Program
    {
        #region  比较两个数字大小，返回最大值
        //不想实例化
        //static int GetMax( int a, int b)
        //{
        //    if (a > b)
        //    {
        //        return a;
        //    }
        //    else
        //    {
        //        return b;

        //    }
        //}
        #endregion

        #region 函数练习题2
        //返回给用户一个登录的结果，并且还要单独的返回给用户的一个登录信息
        //如果用户名错误，除了返回登录结果之外，还要返回一个“用户名错误”、“密码错误”

        //static bool Login(string Username,string passWorld,out string loginInfo)

        //{
        //    loginInfo = "";
        //    if (Username == "admin" && passWorld == "999999")
        //    {
        //        loginInfo = "登录成功";
        //        return true;
        //    }
        //    //代表登录不成功
        //    else
        //    {
        //        if(Username != "admin")
        //        { 
        //            loginInfo = "用户名错误\n"; 
        //        }
        //        if (passWorld != "999999")
        //        {
        //            loginInfo += "密码错误";
        //        }
        //        return false;

        //    }

        //}


        #endregion

        #region 函数练习 第一题 
        //写函数
        static bool method(string UserName, string PassWord, out UserInfo methodInfo)
        {
            methodInfo = new UserInfo();


            if (UserName == "admin" && PassWord == "888888")
            {
                methodInfo.userName = UserName;
                methodInfo.password = PassWord;
                methodInfo.info = "登录成功";
                return true;
            }
            else
            {
                if (UserName != "admin")
                {
                    methodInfo.info= "用户名错误\n";
                }
                if (PassWord != "999999")
                {
                    methodInfo.info = "密码错误\n";
                }
                return false;
            }
        }
        


        #endregion




        static void Main(string[] args)
        {
            #region 第一题 用结构体描述一个学生的信息（name sex age hobby）
            //StuInform xiaohua = new StuInform();//调用student的构造函数，去内存中开辟空间
            //xiaohua.name = "xiaohua";
            //xiaohua.sex = "男";
            //xiaohua.age = 20;
            //xiaohua.hobby = "play footboll";
            //Console.WriteLine("小花的学生信息为：\n {0}\n {1}\n {2}\n {3}\n",xiaohua.name,xiaohua.sex,xiaohua.age,xiaohua.hobby);


            #endregion

            #region 第二题 描述二维坐标
            //vector zuobiao = new vector();
            //zuobiao.x = 5;
            //zuobiao.y = 5;
            //Console.SetCursorPosition(zuobiao.x*2, zuobiao.y);//光标移动到这个位置
            //Console.WriteLine("*");
            #endregion


            #region 数组概念

            //数组：连续的，有顺序的集合
            //数组的声明

            //数据类型 [] 数组名；
            //数据类型 [] 数组名 = new 数类型[长度]
            //数据类型[]数组名 ={元素1，元素2，元素3...}

            //int[] arr1 = new int[10] {0,1,2,3,4,5,6,7,8,9 };
            //Console.WriteLine(arr1[2]);

            //数组元素的访问，通过下标号去访问 数组名[下标号]

            //元素的更改，可以通过下标号访问到你要更改的元素，然后重新赋值
            //arr1[2] = 235;
            //Console.WriteLine(arr1[2]);

            //遍历————把所有的元素都访问一遍
            //数组该怎么遍历？
            //遍历数组：下标号从0开始到数组长度-1结束
            //用for循环适合遍历


            //数组属性：
            // .Length：代表你数组的长度（非静态调用）
            //for (int i = 0; i < arr1.Length-1; i++)//arr1.Length-1 -1原因是下标从0开始
            //{
            //    Console.WriteLine(arr1[i]);
            //}
            #endregion

            #region 数组练习题

            #region 第一题 创建一个数组A，值与下标一样

            //要把功能拆开写

            //填充数据
            //int[] A = new int[10];
            //for (int i = 0; i < A.Length; i++)
            //{
            //    A[i] = i;
            //}
            ////打印数据
            //for (int i = 0; i < A.Length; i++)
            //{
            //    Console.WriteLine(A[i]);
            //}
            //Console.WriteLine("_________________________________________");
            //new 在内存中开辟空间，如果没有赋值，则附上默认值 数字是0 字符串是空串
            #endregion


            //数组的掌控——————通过下标号完成
            //要清楚知道自己下标号指代的是哪一个元素

            #region 第二题 创建另一个数组B，将数组A中每个元素的值乘以2存入数组B

            //int[] B = new int[A.Length]; //这里可以直接用A.Length
            ////访问A中的每一个元素
            //for (int i=0;i<A.Length;i++)
            //{
            //    B[i] = A[i] * 2;
            //}
            ////打印数据
            //for (int i = 0; i < A.Length; i++)
            //{
            //    Console.WriteLine(B[i]);
            //}
            #endregion

            #region 第三题 从一个整数数组中找出最大值、最小值、总和、平均值（可以使用随机数1-100）

            //int[] arr = new int[10];
            //Random r = new Random();


            //int sum = 0;
            //int avg = 0;



            ////赋值
            //for (int i = 0; i < arr.Length; i++)
            //{
            //    arr[i] = r.Next(0, 101);//利用Random函数的属性
            //}
            //int Max = arr[0];
            //int min = arr[0];

            ////打印
            //for (int i = 0; i < arr.Length; i++)
            //{
            //    Console.WriteLine(arr[i]);
            //}

            ////比较数字
            //for (int i = 0; i < arr.Length; i++) 
            //{
            //    sum += arr[i];//每一个arr数据相加
            //    if (Max < arr[i]) //如果当前最大值小于某个数据，那么就重新赋值
            //    {
            //        Max = arr[i];
            //    }


            //}
            //for (int i = 0; i < arr.Length; i++)
            //{
            //    if (min > arr[i])
            //    {
            //        min = arr[i];
            //    }
            //}

            //avg = sum / arr.Length;//求平均值
            //Console.WriteLine("arr数组的总和为{0}，平均值为{1}，最大值为{2}，最小值为{3}",sum,avg,Max,min);
            #endregion

            #region 第四题 交换这个数组中的第一个和最后一个，第二个和倒数第二个，以此类推，把数组进行反转
            //for (int i = 0; i < (arr.Length)/2; i++)//除以2是因为只交换一半就可以交换完了   奇数也是一样的
            //{
            //    int temp = arr[i];
            //    arr[i] = arr[arr.Length-1-i];
            //    arr[arr.Length - 1 - i] = temp;
            //}
            //for (int i = 0; i < arr.Length; i++)
            //{
            //    Console.WriteLine(arr[i]);
            //}

            //Console.WriteLine("_____________________________________________");

            #endregion

            #region 第五题 将数组用|分割输出，如10|108|99|5
            //for (int i = 0; i < arr.Length; i++)
            //{
            //    if (i == arr.Length - 1)
            //    {
            //        Console.WriteLine(arr[i]);
            //    }
            //    else
            //    Console.Write(arr[i]+"|");
            //}
            #endregion

            #region 二维数组基本概念

            //二维数组：  数据类型 [,]数组名 =仅指定长度的初始值

            //          数据类型  [,]数组名 = 初始值

            //  定义一个2行3列的整型二维数组
            //  int[,]numbers=new int [2,3];//第一个表示数组中有几个数组，第二个表示每个数组里面有几个元素
            //  也可以用赋初始值的方法定义
            //  int[,] numbers = new int[,]{{1,2,3},{4,5,6}};

            //二维数组的访问 也是通过下标号访问
            // arr[i,j] i:你在哪一个数组中，j：代表你在该数组中的第几位
            //赋值也可以直接通过下标号赋值
            // 比如：int [,]nums=new int [2,3];
            //      nums[0,0]=1;

            #endregion

            #region 二维数组遍历

            //双层for循环，第一层遍历第一个维度，第二层遍历第二个维度
            // 方法：
            //    数组名.GetLength(index)//从0开始，0代表第一个维度，1代表第二个维度

            //int[,] nums = new int[2, 3];
            //nums[0, 0] = 1;
            //nums[0, 1] = 2;
            //nums[0, 2] = 3;
            //nums[1, 0] = 4;
            //nums[1, 1] = 5;
            //nums[1, 2] = 6;

            //for (int i = 0; i < nums.GetLength(0); i++)
            //{
            //    for (int j = 0; j < nums.GetLength(1); j++)
            //    {
            //        Console.WriteLine(nums[i,j]);
            //    }
            //}


            #endregion

            #region 二维数组习题


            #region 第一题 将1到25赋值给一个二维数组（5行5列）
            //int[,] nums = new int[5, 5];
            //int num = 1;//直接在外面赋值
            ////赋值
            //for (int i = 0; i < nums.GetLength(0); i++)
            //{
            //    for (int j = 0; j < nums.GetLength(1); j++)
            //    {
            //        nums[i, j] = num;
            //        num++;
            //    }
            //}
            ////输出
            //for (int i = 0; i < nums.GetLength(0); i++)
            //{
            //    for (int j = 0; j < nums.GetLength(1); j++)
            //    {
            //        Console.Write(nums[i,j]+"\t");
            //    }
            //    Console.WriteLine();
            //}
            #endregion

            #region 第二题 将二维数组的4行六列的右上部分置0
            //赋值
            //string [,] nums = new string[4, 6];
            //for (int i = 0; i < nums.GetLength(0); i++)
            //{
            //    for (int j = 0; j < nums.GetLength(1); j++)
            //    {
            //        if ((i>=0&&i <= 1) && (j >=3 && j <= 5))
            //        {
            //            nums[i, j] = " ";
            //        }
            //        else 
            //        {
            //            nums[i, j] = "█";
            //        }
            //    }
            //}
            ////输出
            //for (int i = 0; i < nums.GetLength(0); i++)
            //{
            //    for (int j = 0; j < nums.GetLength(1); j++)
            //    {
            //        Console.Write(nums[i,j]+"\t");
            //    }
            //    Console.WriteLine();//这一句挺关键的哈哈哈哈
            //}
            #endregion

            #region 第三题 求二维数组（3行3列）的对角线元素的和

            //  1，  2，  3
            //  4，  5，  6
            //  7，  8，  9

            //i==j 的时候
            //i+j=2的时候
            //答案是：30
            //int[,] nums = new int[3, 3]
            //{
            //    {1,2,3}, 
            //    {4,5,6}, 
            //    {7,8,9}, 

            //};
            //int sum = 0;
            ////赋值
            //for (int i = 0; i < nums.GetLength(0); i++)
            //{
            //    for (int j = 0; j < nums.GetLength(1); j++)
            //    {
            //        if (i == j)
            //        {
            //            sum +=nums[i, j];
            //        }
            //        if (i + j == 2)
            //        {
            //            sum += nums[i, j];//但是中间数字加了两次（5）
            //        }
            //    }
            //}
            ////输出
            //sum -= nums[1, 1];
            //Console.WriteLine(sum);
            #endregion

            #region 第四题 求二维数组（5行5列）中最大元素值及其行列号（随机1~500）
            ////随机数写法
            //Random r = new Random();
            ////创建五行五列数组
            //int[,] arr = new int[5, 5];
            //for (int i = 0; i < arr.GetLength(0); i++)
            //{
            //    for (int j = 0; j < arr.GetLength(0); j++)
            //    {
            //        arr[i, j] = r.Next(1, 501);//随机赋值
            //    }
            //}

            ////打印
            //for (int i = 0; i < arr.GetLength(0); i++)
            //{
            //    for (int j = 0; j < arr.GetLength(0); j++)
            //    {
            //        Console.Write(arr[i, j] +"\t");
            //    }
            //    Console.WriteLine();
            //}
            //Console.WriteLine("__________________________________________");
            ////行列号用结构体写（第一次尝试）
            ////声明一个行列号
            //vector rownumber = new vector();//代表行列号
            //int max = arr[0,0];//代表最大值，要逐步比较
            ////遍历数组
            //for (int i = 0; i < arr.GetLength(0); i++)
            //{
            //    for (int j = 0; j < arr.GetLength(0); j++)
            //    {
            //        if (max < arr[i, j])
            //        {
            //            //记录最大值和行列号
            //            max = arr[i, j];
            //            rownumber.x = i;
            //            rownumber.y = j;
            //        }
            //    }
            //}
            //Console.WriteLine("该数组最大值是{0}，行列号为({1},{2})",max,rownumber.x+1,rownumber.y+1);//加1是方便阅读


            #endregion

            #region 第五题 从键盘输入9个整数，保存在二维数组中按方阵形式输出

            //int[,] arr = new int[3, 3];
            //for (int i = 0; i < arr.GetLength(0); i++)
            //{
            //    for (int j = 0; j < arr.GetLength(0); j++)
            //    {
            //        //接受用户的输入
            //        Console.WriteLine("请输入数字");
            //        int num = int.Parse( Console.ReadLine());//类型转换
            //        arr[i, j] = num;
            //    }
            //}
            ////输出
            //for (int i = 0; i < arr.GetLength(0); i++)
            //{
            //    for (int j = 0; j < arr.GetLength(0); j++)
            //    {
            //        Console.Write(arr[i, j] + "\t");
            //    }
            //    Console.WriteLine();
            //}
            #endregion


            #endregion

            #endregion


            #region 方法（函数）基本概念

            //封装我们的逻辑 以便重复使用

            //函数（方法）可以有返回值
            //方法得有参数的接入口

            //static 访问修饰符 返回类型 方法名(参数类型,....) //参数类型是形参
            //{
            //    方法体;

            //}
            //如果说你有返回值，返回类型处填上你要返回的数据类型
            //可以在函数中使用return关键字返回对应结果

            //如果说没有返回值，返回类型处用void关键字填充
            //也可以在函数中使用return关键字，结束方法


            //静态方法：被static修饰过的方法叫静态方法
            //特征：调用上，通过类型名称.方法名()

            //非静态方法：没有被static修饰过的方法叫成员方法
            //特征：调用上，必须要先实例化一个对象，再去通过对象名.方法名();

            //函数只能声明在类，结构体，接口中
            //通过形参列表可以传递参数到函数中

            //为什么不包含自身类型的成员
            //因为结构体是存储在栈中
            //因为栈很小
            //如果包含自己，会不断的展开自身，把栈堆满
            //导致爆栈，所以不能包含自身成员
            //但是可以包含其他结构体类型的成员，因为不会无限展开
            //结构体是值类型

            //重点知识：
            //传参：值类型与引用类型
            //值类型：存在栈中（结构体是值类型）
            //值类型传参特征：就是在栈中复制了一份值


            //引用类型：存在堆中，地址存在栈中
            //引用类型传参特征：因为复制的是地址，而地址会指向同一个空间，所以会更改原内容
            //所以你如果在函数中更改内容则会改变内容，所以要拿到地址

            //为了让值类型传参可以修改原内容，出现了一个关键字
            //ref关键字
            //使用方法：1.在定义函数的参数列表时，把你想要的索引的值类型的那个参数前加上ref
            //        2.在调用方法时，在传递参数时，依然要写上ref


            #endregion


            #region 方法练习——怪物

            //Monster xiaomei = new Monster();
            //xiaomei.name = "xiaomei";
            //xiaomei.atk = 100;
            //xiaomei.hp = 200;

            ////制造对手
            //Monster xiaoqiang = new Monster();
            //xiaoqiang.name = "小强";
            //xiaoqiang.atk = 100;
            //xiaoqiang.hp = 1800;

            ////小美攻击小强
            //xiaomei.Attack(ref xiaoqiang);//小美攻击小强
            ////2.在调用方法时，在传递参数时，依然要写上ref
            ////关键字ref要一起使用
            //Console.WriteLine("小强还有多少血量"+xiaoqiang.hp);

            #endregion


            #region 比较数字大小
            //int max= GetMax( 50, 100);
            //Console.WriteLine(max);
            #endregion

            #region  关键字学习

            #region out
            /*
             * 可以使用数组或结构体返回多个数据，也可以使用基本数据类型返回单一数据
             * 被out修饰的参数在函数内部是需要被赋值的参数
             * 在函数调用的时候，out参数前一定要加out
             */
            #endregion

            #region ref
            /*
             * 使用变量的地址
             * 直接修改类型实参的值
             * 变量如果使用ref进行传参，必须先赋值
             * 在函数调用的时候，ref参数前一定要加ref
             */
            #endregion

            #region 练习
            //返回给用户一个登录的结果，并且还要单独的返回给用户的一个登录信息
            //如果用户名错误，除了返回登录结果之外，还要返回一个“用户名错误”、“密码错误”

            //Console.WriteLine("请输入用户名： ");
            //string id = Console.ReadLine();
            //Console.WriteLine("请输入密码： ");
            //string password = Console.ReadLine();
            //string loginInfo = " ";

            //bool temp = Login(id,password,out loginInfo);
            //Console.WriteLine(loginInfo);


            #endregion

            #region 关键字
            /*
             * this---指代自身实例对象
             * ref----让值类型传参对实际参数有作用---（当做指针传地址）
             * out---可以额外输出一个信息（比如登录成功）
             * 
             *out ：
             *    1）在定义函数参数列表时，可在参数前添加
             *    2）在函数跳出前，一定要先赋值，不然会报错
             *    3）在函数调用时，在被out修饰过的参数前，要加out
             *    
             *ref ：
             *    1）在定义函数参数列表时，可在参数前添加
             *    2）在调用前，ref的参数一定要先赋值（赋值了才能使用）
             *    3）在函数调用时，在被ref修饰过的参数前，要加ref
             * 
             */
            #endregion

            #endregion


            #region 函数练习题

            #region 第一题 

            //写一个方法来判断用户输入的是否正确，如果正确则返回用户名和密码 及用户信息

            //1.是否正确--bool类型
            //2.连串信息————封装成结构体


            //写登录
            Console.WriteLine("请输入用户名：");
            string name = Console.ReadLine();
            Console.WriteLine("请输入密码：");
            string passWord = Console.ReadLine();
            UserInfo Logininfo;//这里是自定义的结构体变量，别调用错了
            //调用函数
            bool temp=method(name,passWord,out Logininfo);
            if (temp == true)
            {
                Console.WriteLine(Logininfo.info);
                Console.WriteLine(Logininfo.userName);
                Console.WriteLine(Logininfo.password);
            }
            else
            {
                Console.WriteLine(Logininfo.info);
            }
            #endregion

            #endregion




        }
    }
}
